/**   
* @Title: AnnotationUtils.java 
* @Package net.gdface.codegen.base 
* @Description: TODO 
* @author guyadong   
* @date 2015年7月31日 上午10:02:34 
* @version V1.0   
*/
package com.gitee.l0km.codegen.base;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.gitee.l0km.codegen.annotations.DeriveMethod;
import com.gitee.l0km.codegen.annotations.Service;
import com.gitee.l0km.com4j.base.Assert;

/**
 * @author guyadong
 *
 */
public class AnnotationUtils {
	private static final Logger logger = LoggerFactory.getLogger(AnnotationUtils.class);
	public final static String PATTERN_NOT_BLANK="^\\w+$";

	public static  final Service getServiceAnnotation(Class<?> clazz) throws InvalidNameException,
			InvalidAnnotationDefineException {
		Service def = clazz.getAnnotation(Service.class);
		if (null != def) {
			if (def.portPrefix().isEmpty()
					&& (def.bridgeType() == Object.class || def.targetType() == Object.class || def.genericTypes().length == 0)) {
				logger.warn("Invalid annotation  {} define in {}\nbridgeType={},targetType={},genericTypes={}",
						Service.class.getSimpleName(), clazz.getSimpleName(), def.bridgeType().getSimpleName(), def
								.targetType().getSimpleName(), Arrays.toString(def.genericTypes()));
				def = null;
			} else {
				if (def.bridgeType() == def.targetType())
					throw new InvalidAnnotationDefineException(String.format(
							"bridgeType must not equals targetType of annotation %s in class %s",
							Service.class.getSimpleName(), clazz.getName()));
				String[] types = def.genericTypes();
				Class<?>[] classes = def.genericTypeClasses();
				if (types.length != classes.length)
						throw new InvalidAnnotationDefineException(String.format(
									"genericTypes and genericTypeClasses has different elements number in annotation %s from class %s",
									Service.class.getSimpleName(), clazz.getName()));
				for (String type : types) {
					if (!type.matches(PATTERN_NOT_BLANK))
						throw new InvalidNameException(
								String.format(
										"the string from genericTypes() of annotation [%s] in class %s must not have space char ",
										Service.class.getSimpleName(), clazz.getName()));
				}
				Set<Class<?>> classSet;
				if (CodeGenUtils.hasDuplicative(types))
					throw new InvalidAnnotationDefineException(String.format(
							"genericTypes has duplicated elements in annotation %s from class %s",
							Service.class.getSimpleName(), clazz.getName()));
				if (null == (classSet = CodeGenUtils.toSetIfnotDup(classes)))
					throw new InvalidAnnotationDefineException(String.format(
							"genericTypeClasses has duplicated elements in annotation %s from class %s",
							Service.class.getSimpleName(), clazz.getName()));
				else if (classSet.contains(Object.class))
					throw new InvalidAnnotationDefineException(String.format(
							"genericTypeClasses must not contains Object.class in annotation %s from class %s",
							Service.class.getSimpleName(), clazz.getName()));
			}
		}
		return def;
	}
	
	public static  final DeriveMethod getDeriveMethodAnnotation(Method method,ServiceInfo serviceInfo) throws InvalidNameException,
	InvalidAnnotationDefineException {
		Assert.notNull(method, "method");
		Assert.notNull(serviceInfo, "serviceInfo");
		DeriveMethod dm=method.getAnnotation(DeriveMethod.class);
		if(dm!=null){
			Set<Class<?>> localClassSet;
			if(null==(localClassSet=CodeGenUtils.toSetIfnotDup(dm.localResolvedTypes())))		
				throw new InvalidAnnotationDefineException(String.format(
						"localResolvedTypes has duplicated elements in annotation %s from class %s",
						DeriveMethod.class.getSimpleName(), method.getName()));		
			else if(localClassSet.contains(serviceInfo.getTargetType()))
				throw new InvalidAnnotationDefineException(String.format(
						"localResolvedTypes must not contains %s.class in annotation %s from class %s",
						serviceInfo.getTargetType().getName(),DeriveMethod.class.getSimpleName(), method.getName()));
			Set<Class<?>> remoteClassSet;
			if(null==(remoteClassSet=CodeGenUtils.toSetIfnotDup(dm.remoteResolveTypes())))		
				throw new InvalidAnnotationDefineException(String.format(
						"remoteResolveTypes has duplicated elements in annotation %s from class %s",
						DeriveMethod.class.getSimpleName(), method.getName()));		
			else if(remoteClassSet.contains(serviceInfo.getTargetType()))
				throw new InvalidAnnotationDefineException(String.format(
						"remoteResolveTypes must not contains %s.class in annotation %s from class %s",
						serviceInfo.getTargetType().getName(),DeriveMethod.class.getSimpleName(), method.getName()));
			if(remoteClassSet.contains(String.class))
				throw new InvalidAnnotationDefineException(String.format(
						"remoteResolveTypes must not have String.class(String不能做为衍生方法类型) in annotation %s from class %s",
						DeriveMethod.class.getSimpleName(), method.getName()));
			Map<String, Class<?>> genericTypeMap = serviceInfo.getGenericTypeMap();
			for (Class<?> clazz : remoteClassSet) {
				if (!genericTypeMap.containsValue(clazz))
					throw new InvalidAnnotationDefineException(
							String.format(
									"%s in remoteResolveTypes in annotation %s from class %s not be invalid genericType(不是有效的衍生方法类型),because not found in annotation %s ",
									DeriveMethod.class.getSimpleName(), method.getName(), Service.class.getSimpleName()));
			}
		}
		return dm;
		
	}
}
